package bloodfang.gui;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import bloodfang.Race;

public class CharacterReader {
	private HashMap<String,Integer> items = new HashMap<String,Integer>();
	private final HashMap<Slot,EquippedItem> equippedItems = new HashMap<Slot,EquippedItem>();
	private final Race race;

	public CharacterReader(String playername,String server,String region) throws JSONException,Exception {
		
		server = server.replaceAll(" ", "%20");
		String json = loadURL(region,server,playername);
		JSONObject js = null;
		File dbDir = new File("/cache/");
		if(!dbDir.exists())
			dbDir.mkdir();
		File file = new File("/cache/" + region.toLowerCase() + "-" + server.toLowerCase()+"-"+playername.toLowerCase()+".character");
		try {
			js = new JSONObject(json);
		} catch (JSONException e) {
			e.printStackTrace();
		}
		
		try {
			PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(file)));
			out.write(json);
			out.flush();
			out.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		JSONObject items = (JSONObject) js.get("items");
		for ( Iterator<?> i = items.keys(); i.hasNext(); )
		{
			String s = (String) i.next();
			Object item = items.get(s);
			if(item instanceof Integer){
				
			}
			else {
				int id = ((JSONObject)item).getInt("id");
				this.items.put(s, id);
			}
		}
		for( String name: this.items.keySet() )
	    {
			if(Slot.valueOf(name) == Slot.shirt || Slot.valueOf(name) == Slot.tabard) continue;
			int itemid = this.items.get(name);
			EquippedItem item = new EquippedItem();
			item.item_id = itemid;
			
			// enchant etc.
			JSONObject iteme = new JSONObject();
			if(items.has(name))
				iteme = (JSONObject) items.get(name);
			
			JSONObject tooltip = null;
			if(iteme.has("tooltipParams")){
				tooltip = (JSONObject) iteme.get("tooltipParams");
				if(tooltip.has("upgrade")){
					JSONObject upgrade = (JSONObject) tooltip.get("upgrade");
					if(upgrade.has("current")){
						int upgrade_level = upgrade.getInt("current");
						item.setUpgradeLevel(upgrade_level);
					}
				}
				if(tooltip.has("enchant")){
					int enchantid = tooltip.getInt("enchant");
					item.setEnchant(enchantid);
				}
				if(tooltip.has("gem0")){
	    		   int gemid = tooltip.getInt("gem0");
	    		   item.gem_ids[0] = gemid;
				}
				if(tooltip.has("gem1")){
	    		   int gemid = tooltip.getInt("gem1");
	    		   item.gem_ids[1] = gemid;
				}
				if(tooltip.has("gem2")){
	    		   int gemid = tooltip.getInt("gem2");
	    		   item.gem_ids[2] = gemid;
				}
				if(tooltip.has("suffix")){
					int suffixid = Math.abs(tooltip.getInt("suffix"));
					item.setRandomSuffix(suffixid);
				}
			}
	       
			this.equippedItems.put(Slot.valueOf(name), item);
//			this.itemDB.put(item.getItem().getId(), baseItem);
	    }
		
		// Class
		//base.setCharacterClass(CharacterClass.values()[js.getInt("class")-1]);
		
		// Race
		int raceid = js.getInt("race");
		if(Race.pandarenIds.contains(raceid))
			race = Race.pandaren;
		else{
			Race found = null;
			for(Race race : Race.values()){
				if(race.getIndex() == raceid){
					found = race;
					break;
				}
			}
			this.race = found;
		}
		
		// Professions
		JSONObject profession = js.getJSONObject("professions");
		JSONArray professions = profession.getJSONArray("primary");
		for(int i = 0;i < professions.length(); i++) {
			JSONObject prof = (JSONObject) professions.get(i);
			//base.addProfession(Profession.valueOf(prof.getString("name")));
		}
		
		//GlyphDB gDB = new GlyphDB();
		HashMap<String, Integer> specMap = new HashMap<String,Integer>();
		specMap.put("a", 0); specMap.put("Z", 1); specMap.put("b", 2); specMap.put("Y", 3);
		// talents, glyphs
		JSONArray talents = (JSONArray) js.get("talents");
		for(int i = 0;i < talents.length(); i++) {
			JSONObject spec = (JSONObject) talents.get(i);
			//Spec[] classSpecs = Spec.getSpecsByCharacterClass(base.getCharacterClass());
			String calcSpec = spec.getString("calcSpec");
			List<String> glyphnames = new ArrayList<String>();
			for(String glyphcat : JSONObject.getNames(spec.getJSONObject("glyphs"))){
				JSONArray glyphs = spec.getJSONObject("glyphs").getJSONArray(glyphcat);
				for(int g = 0; g < glyphs.length(); g++){
					//glyphnames.add(gDB.getGlyph(glyphs.getJSONObject(g).getInt("glyph")).getName());
				}
			}
			
//			if((spec.has("selected") && spec.getBoolean("selected"))){
//				if(spec.has("spec")){
//					this.base.setSpec(classSpecs[specMap.get(calcSpec)]);
//					this.base.setTalents(spec.getString("calcTalent"));
//					this.base.setGlyphs(glyphnames);
//				} else {
//					this.base.setSpec(Spec.Combat);
//				}
//			}else{
//				if(spec.has("spec")){
//					this.base.setOffSpec(classSpecs[specMap.get(calcSpec)]);
//					this.base.setOffTalents(spec.getString("calcTalent"));
//					this.base.setOffGlyphs(glyphnames);
//				} else {
//					this.base.setOffSpec(Spec.Subtlety);
//				}
//			}
		}
		
		// achievements
		// "achievements":{"achievementsCompleted"
		JSONObject achievements = js.getJSONObject("achievements");
		JSONArray achievementsCompleted = achievements.getJSONArray("achievementsCompleted");
		for(int i = 0; i < achievementsCompleted.length(); i++){
			//System.out.println(achievementsCompleted.getInt(i));
			//base.getAchievements().add(achievementsCompleted.getInt(i));
		}
		
		System.out.println(js.getString("name") + " - Level " + js.getInt("level"));
		
//		for( String name: this.base.getSetItems() ) {
//			System.out.println(name + ": piece/s");
//	    }
//		for( String name: this.base.getGearBuffs() ) {
//			System.out.print(name + ", ");
//	    }
//		System.out.println();
	}
	
	private String loadURL(String region, String server, String playername) throws Exception {
		
		BufferedReader in;
		try {
			File file = new File("/cache/" + region.toLowerCase() + "-" + server.toLowerCase()+"-"+playername.toLowerCase()+".character");
			in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));  
			String content = in.readLine();
			in.close();
			return content;
		} catch (IOException es) {
			//throw new CharacterNotFoundException("Character not found");
		}
		String url1 = "http://%s.battle.net/api/wow/character/%s/%s?fields=items,talents,stats,professions,achievements";
		String url = String.format(url1, region, server, playername);
		InputStream is = null;
		BufferedReader rd = null;
		try {
			is = new URL(url).openStream();
			rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
		} catch (FileNotFoundException e) {
			throw new Exception("Character not found");
		} catch (MalformedURLException e) {
			e.printStackTrace();
		} catch (IOException e) {
			//e.printStackTrace();
			//BufferedReader in;
			try {
				File file = new File("./cache/" + region.toLowerCase() + "-" + server.toLowerCase()+"-"+playername.toLowerCase()+".character");
				in = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));  
				String content = in.readLine();
				in.close();
				return content;
			} catch (IOException es) {
				throw new Exception("Character not found");
			}
		}
		String cp = "";
		StringBuilder sb = new StringBuilder();
		try {
			while ((cp = rd.readLine()) != null) {
			      sb.append(cp);
			}
		} catch (IOException e) {
			e.printStackTrace();
		}
		try {
			is.close();
			rd.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
		return sb.toString();
	}

	public Race getRace() {
		return this.race;
	}
	
	public HashMap<Slot,EquippedItem> getEquippedItems() {
		return equippedItems;
	}
}	
